﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ProDivingAdmin2salmon14
{
    public partial class FormMain : Form, IFormMain
    {
        #region Private members
        private List<Image> dots = new List<Image>();
        private BackgroundWorker checkJudges = new BackgroundWorker();
        private BackgroundWorker checkJudgesScore = new BackgroundWorker();
        private List<Tuple<PictureBox, TextBox, Label>> judgeConnectionAndScore = new List<Tuple<PictureBox, TextBox, Label>>();
        private int diveOrderCounter = 0;
        private StartUpForm startUpForm = new StartUpForm();
        private DiverForm diverForm = new DiverForm();
        private AddDataForm addDataForm = new AddDataForm();
        #endregion

        public FormMain(StartUpForm startUpForm, DiverForm diverForm, AddDataForm addDataForm)
        {
            this.startUpForm = startUpForm;
            this.diverForm = diverForm;
            this.addDataForm = addDataForm;
            InitializeComponent();

            this.judgeConnectionAndScore.Add(new Tuple<PictureBox, TextBox, Label>(this.Judge1Connection, this.Judge1Score, this.Judge1Label));
            this.judgeConnectionAndScore.Add(new Tuple<PictureBox, TextBox, Label>(this.Judge2Connection, this.Judge2Score, this.Judge2Label));
            this.judgeConnectionAndScore.Add(new Tuple<PictureBox, TextBox, Label>(this.Judge3Connection, this.Judge3Score, this.Judge3Label));
            this.judgeConnectionAndScore.Add(new Tuple<PictureBox, TextBox, Label>(this.Judge4Connection, this.Judge4Score, this.Judge4Label));
            this.judgeConnectionAndScore.Add(new Tuple<PictureBox, TextBox, Label>(this.Judge5Connection, this.Judge5Score, this.Judge5Label));
            this.judgeConnectionAndScore.Add(new Tuple<PictureBox, TextBox, Label>(this.Judge6Connection, this.Judge6Score, this.Judge6Label));
            this.judgeConnectionAndScore.Add(new Tuple<PictureBox, TextBox, Label>(this.Judge7Connection, this.Judge7Score, this.Judge7Label));
            this.judgeConnectionAndScore.Add(new Tuple<PictureBox, TextBox, Label>(this.Judge8Connection, this.Judge8Score, this.Judge8Label));
            this.judgeConnectionAndScore.Add(new Tuple<PictureBox, TextBox, Label>(this.Judge9Connection, this.Judge9Score, this.Judge9Label));

            this.dots.Add(ProDivingAdmin2salmon14.Properties.Resources.RedDot1);
            this.dots.Add(ProDivingAdmin2salmon14.Properties.Resources.GreenDot);

            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;

            this.checkJudges.DoWork += new DoWorkEventHandler(CheckJudgesWork);
            this.checkJudges.ProgressChanged += new ProgressChangedEventHandler(CheckJudgesProgress);
            this.checkJudges.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CheckJudgesWorkDone);

            this.checkJudgesScore.DoWork += new DoWorkEventHandler(CheckJudgesScoreWork);
            this.checkJudgesScore.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CheckJudgesScoreWorkDone);

            this.checkJudges.WorkerSupportsCancellation = true;
            this.checkJudges.WorkerReportsProgress = true;

            this.checkJudgesScore.WorkerSupportsCancellation = true;

            this.NextDiveButton.Click += new EventHandler(OnNextDive);

            if (!checkJudges.IsBusy) 
            {
                checkJudges.RunWorkerAsync();
            }
        }

        #region Click events
        private void newContestToolStripMenuItem_Click(object sender, EventArgs e)
        {

            System.Windows.Forms.DialogResult result = this.startUpForm.ShowDialog();

            if (result == System.Windows.Forms.DialogResult.OK)
            {
                if (EventResetData != null)
                {
                    if (EventGetIsFemaleData != null)
                    {
                        if (EventGetMinAge != null)
                        {
                            if (EventGetDivingHeight != null)
                            {
                                if (EventGetJudges != null)
                                {
                                    if (EventGetJudgesPath != null)
                                    {
                                        if (EventGetDiversPath != null)
                                        {
                                            EventResetData(EventGetIsFemaleData(), EventGetMinAge(), EventGetDivingHeight(), EventGetJudges(), EventGetDiversPath(), EventGetJudgesPath());
                                            for (int i = EventGetJudges(); i < 9; i++) 
                                            {
                                                judgeConnectionAndScore[i].Item1.Hide();
                                                judgeConnectionAndScore[i].Item2.Hide();
                                                judgeConnectionAndScore[i].Item3.Hide();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if (EventGetDiverOrder != null)
                {
                    this.dataGridViewDiveOrder.ReadOnly = true;
                    this.dataGridViewDiveOrder.DataSource = new BindingList<DisplayDive>(EventGetDiverOrder());

                    this.dataGridViewRanking.ReadOnly = true;
                    this.dataGridViewRanking.DataSource = new BindingList<Diver>(EventGetDiverList());


                    this.dataGridViewDiveOrder.Columns["orderNumber"].HeaderText = "Order";
                    this.dataGridViewDiveOrder.Columns["diverName"].HeaderText = "Name";
                    this.dataGridViewDiveOrder.Columns["diverNationality"].HeaderText = "Nationality";
                    this.dataGridViewDiveOrder.Columns["diveCode"].HeaderText = "Dive code";
                    this.dataGridViewDiveOrder.Columns["diveHeight"].HeaderText = "Dive height";
                    this.dataGridViewDiveOrder.Columns["diveDificulty"].HeaderText = "DD";
                    this.dataGridViewDiveOrder.Columns["diveName"].HeaderText = "Dive name";
                    
                    this.dataGridViewDiveOrder.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
                    this.dataGridViewDiveOrder.Columns["diveName"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                }
            }
        }

        private void OnNextDive(object sender, EventArgs e)
        {
            if (!this.checkJudgesScore.IsBusy)
            {
                NextDiveButton.Enabled = false;
                if (this.SetNextAndCurrentDiver())
                {
                    this.diveOrderCounter++;
                    if (EventNextDive != null)
                    {
                        EventNextDive();
                    }
                    foreach (var judge in judgeConnectionAndScore) 
                    {
                        judge.Item2.Text = "0";
                    }
                    this.JudgeTotalScore.Text = "";

                    checkJudgesScore.RunWorkerAsync();
                }
                else 
                {
                    MessageBox.Show(this, "Congratulations, contest done!", "Done!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                }
            }

            this.dataGridViewRanking.ReadOnly = true;
            this.dataGridViewRanking.DataSource = new BindingList<Diver>(EventGetDiverList());
        }
        #endregion

        #region BackgroundWorkers
        private void CheckJudgesWorkDone(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled == true) 
            {
                System.Console.WriteLine("CheckJudges cancelled");
            }
            else if (!(e.Error == null))
            {
                System.Console.WriteLine("An error with CheckJudges occured");
            }
            else 
            {
                System.Console.WriteLine("CheckJudges complete!");
            }
        }

        private void CheckJudgesProgress(object sender, ProgressChangedEventArgs e) 
        {
            List<Judge> connectedJudgeList = (List<Judge>)e.UserState;

            foreach (var judge in connectedJudgeList) 
            {
                if (judge.isConnected)
                {
                    if (this.JudgeTotalScore.Text == "")
                    {
                        this.JudgeTotalScore.Text = "0";
                    }

                    if (judgeConnectionAndScore[judge.order].Item2.Text == "0") 
                    {
                        this.JudgeTotalScore.Text = (float.Parse(this.JudgeTotalScore.Text) + judge.score).ToString();
                    }

                    judgeConnectionAndScore[judge.order].Item1.Image = dots[1];
                    judgeConnectionAndScore[judge.order].Item2.Text = judge.score.ToString();
                }
                else 
                {
                    judgeConnectionAndScore[judge.order].Item1.Image = dots[0];
                    judgeConnectionAndScore[judge.order].Item2.Text = "DC";
                }
            }
        }

        private void CheckJudgesWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = (BackgroundWorker)sender;
            int counter = 0;
            while (true)
            {
                if (worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    if (EventGetConnectedJudgeList != null) 
                    {
                        worker.ReportProgress(counter, EventGetConnectedJudgeList());
                    }
                    if (EventGetIsDone != null) 
                    {
                        if (EventGetIsDone()) 
                        {
                            worker.CancelAsync();
                        }
                    }

                    counter++;
                    System.Console.WriteLine("CheckJudges did a check");
                    System.Threading.Thread.Sleep(3000);
                }
            }
        }

        private void CheckJudgesScoreWorkDone(object sender, RunWorkerCompletedEventArgs e) 
        {
            if (e.Cancelled == true)
            {
                MessageBox.Show(this, "Contest is done!", "Contest done");
                System.Console.WriteLine("CheckJudgesScore cancelled");
            }
            else if (!(e.Error == null))
            {
                System.Console.WriteLine("An error with CheckJudgesScore occured");
            }
            else
            {
                System.Console.WriteLine("CheckJudgesScore complete!");

                if ((diveOrderCounter + 1) == this.dataGridViewDiveOrder.RowCount)
                {
                    MessageBox.Show(this, "Congratulations, contest done!", "Done!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                }
                else 
                {
                NextDiveButton.Enabled = true;
            }
        }
        }

        private void CheckJudgesScoreWork(object sender, DoWorkEventArgs e) 
        {
            BackgroundWorker worker = (BackgroundWorker)sender;
            bool isBreak = false;

            while (!isBreak) 
            {
                if (worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    break;
                }
                else 
                {
                    System.Threading.Thread.Sleep(3000);
                    if (EventGetIsNextDive != null)
                    {
                        isBreak = EventGetIsNextDive();

                    }
                }
            }
        }
        #endregion

        #region Private methods
        private bool SetNextAndCurrentDiver() 
        {
            try
            {
                this.CurrentDiverNameLabel.Text = this.dataGridViewDiveOrder["diverName", this.diveOrderCounter].Value.ToString();

                if (this.CurrentDiverNameLabel.Text.Length > 16)
                {
                    this.CurrentDiverNameLabel.Text = this.CurrentDiverNameLabel.Text.Remove(14);
                    this.CurrentDiverNameLabel.Text = this.CurrentDiverNameLabel.Text.PadRight(16, '.');
                }

                this.CurrentDiverNationalityLabel.Text = this.dataGridViewDiveOrder["diverNationality", this.diveOrderCounter].Value.ToString();
                this.CurrentDiveCodeLabel.Text = this.dataGridViewDiveOrder["diveCode", this.diveOrderCounter].Value.ToString();
                this.CurrentDiveNameLabel.Text = this.dataGridViewDiveOrder["diveName", this.diveOrderCounter].Value.ToString();

                if (this.CurrentDiveNameLabel.Text.Length > 24)
                {
                    this.CurrentDiveNameLabel.Text = this.CurrentDiveNameLabel.Text.Remove(20);
                    this.CurrentDiveNameLabel.Text = this.CurrentDiveNameLabel.Text.PadRight(24, '.');
                }

                this.CurrentDDLabel.Text = this.dataGridViewDiveOrder["diveDificulty", this.diveOrderCounter].Value.ToString();
                this.CurrentDiverOrderLabel.Text = this.dataGridViewDiveOrder["orderNumber", this.diveOrderCounter].Value.ToString();
            }
            catch (ArgumentOutOfRangeException) 
            {
                this.CurrentDiverNameLabel.Text = "None";
                this.CurrentDiverNationalityLabel.Text = "";
                this.CurrentDiverOrderLabel.Text = "";
                this.CurrentDiveNameLabel.Text = "";
                this.CurrentDDLabel.Text = "";
                this.CurrentDiveCodeLabel.Text = "";
                return false;
            }

            try
            {
                this.NextDiverNameLabel.Text = this.dataGridViewDiveOrder["diverName", this.diveOrderCounter + 1].Value.ToString();
                this.NextDiverNationalityLabel.Text = this.dataGridViewDiveOrder["diverNationality", this.diveOrderCounter + 1].Value.ToString();
                this.NextDiverDiveCodeLabel.Text = this.dataGridViewDiveOrder["diveCode", this.diveOrderCounter + 1].Value.ToString();
                this.NextDiverDDLabel.Text = this.dataGridViewDiveOrder["diveDificulty", this.diveOrderCounter + 1].Value.ToString();
                this.NextDiverOrderLabel.Text = this.dataGridViewDiveOrder["orderNumber", this.diveOrderCounter + 1].Value.ToString();
            }
            catch (ArgumentOutOfRangeException) 
            {
                this.NextDiverNameLabel.Text = "None";
                this.NextDiverNationalityLabel.Text = "";
                this.NextDiverDiveCodeLabel.Text = "";
                this.NextDiverDDLabel.Text = "";
                this.NextDiverOrderLabel.Text = "";
            }
            return true;
        }
        #endregion

        #region Public event declarations

        public event DelegateGetIsDone EventGetIsDone = null;

        public event DelegateGetIsNextDive EventGetIsNextDive = null;

        public event DelegateSendDive EventSendDive = null;

        public event DelegateGetDiverOrder EventGetDiverOrder = null;

        public event DelegateGetAmountOfJudges EventGetAmountOfJudges = null;

        public event DelegateGetConnectedJudgeList EventGetConnectedJudgeList = null;

        public event DelegateNextDive EventNextDive = null;

        public event DelegateDQDiver EventDQDiver = null;

        public event DelegateGetNextDiver EventGetNextDiver = null;

        public event DelegatGetCurrentDiver EventGetCurrentDiver = null;

        public event DelegateGetDiverList EventGetDiverList = null;

        public event DelegateGetCurrentDive EventGetCurrentDive = null;

        public event DelegateCalculateScore EventCalculateScore = null;

        public event DelegateCalculateAllDivers EventCalculateAllDivers = null;

        public event DelegateResetData EventResetData = null;

        public event DelegateGetIsFemaleData EventGetIsFemaleData = null;

        public event DelegateGetMinAge EventGetMinAge = null;

        public event DelegateGetJudges EventGetJudges = null;

        public event DelegateGetDivingHeight EventGetDivingHeight = null;

        public event DelegateGetJudgesPath EventGetJudgesPath = null;

        public event DelegateGetDiversPath EventGetDiversPath = null;

        public event DelegateSaveContest EventSaveContest = null;

        public event DelegateGetContest EventGetContest = null;

        public event DelegateLoadContest EventLoadContest = null;

        public event DelegateSetContest EventSetContest = null;

        #endregion

        private void CurrentDiveNameLabel_MouseHover(object sender, EventArgs e)
        {
            ToolTip tip = new ToolTip();
            tip.SetToolTip(this.CurrentDiveNameLabel, this.dataGridViewDiveOrder["diveName", this.diveOrderCounter].Value.ToString());
        }

        private void disqualifyInjureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.diverForm.ShowDialog();
        }

        private void addEditToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.addDataForm.ShowDialog();
        }

        private void saveAsContestToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveAs = new SaveFileDialog();

            saveAs.OverwritePrompt = true;
            saveAs.Filter = "XML save files (*.xml)|*.xml";

            saveAs.ShowDialog();

            string filePath = saveAs.FileName;

            if (EventSaveContest != null)
            {
                if (EventGetContest != null)
                {
                    EventSaveContest(filePath, EventGetContest());
                }
            }
            
        }

        private void loadContestToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Contest contest = new Contest(true);
            OpenFileDialog open = new OpenFileDialog();

            open.Filter = "XML save files (*.xml)|*.xml";

            open.ShowDialog();

            string filePath = open.FileName;

            if (EventLoadContest != null)
            {
                contest = EventLoadContest(filePath);
            }

            if (EventSetContest != null)
            {
                EventSetContest(contest);
            }

            this.dataGridViewDiveOrder.ReadOnly = true;
            this.dataGridViewDiveOrder.DataSource = new BindingList<DisplayDive>(EventGetDiverOrder());

            this.dataGridViewRanking.ReadOnly = true;
            this.dataGridViewRanking.DataSource = new BindingList<Diver>(EventGetDiverList());
        }
    }
}
